package com.star.common.orm.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.*;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

@SuppressWarnings("all")
public class Converter {
    private static final Logger log = LoggerFactory.getLogger(Converter.class);
    private static final String REFLECT_ERROR = "反射获取转换对象异常";
    private static final String COMMA = ",";

    private Converter() {
    }

    public static void mapToObject(Map map, Object object) {
        if (object != null && map != null) {
            BeanWrapper beanWrapper = new BeanWrapperImpl(object);
            PropertyValues propertyValues = new MutablePropertyValues(map);
            beanWrapper.setPropertyValues(propertyValues, true, true);
        }

    }

    public static String changeColumnToFieldName(String columnName) {
        String[] array = columnName.split(StrPoolUtils.DASH);
        StringBuilder sb = null;

        for (String s : array) {
            String cn = s;
            cn = cn.toLowerCase();
            if (sb == null) {
                sb = new StringBuilder(cn);
            } else {
                sb.append(cn.substring(0, 1).toUpperCase()).append(cn.substring(1));
            }
        }

        return sb != null ? sb.toString() : null;
    }

    public static Map<String, Object> toMap(Object obj) {
        Collection<String> ignoredFieldCol = Sets.newHashSet();
        return toMap(obj, ignoredFieldCol);
    }

    public static Map<String, Object> toMap(Object obj, Collection<String> ignoredFieldCol) {
        if (obj == null) {
            return null;
        } else {
            Map<String, Object> map = Maps.newHashMap();
            if (obj instanceof String) {
                map.put((String) obj, obj);
            } else {
                toMap(obj, map, ignoredFieldCol);
            }
            return map;
        }
    }

    public static void toMap(Object object, Map map) {
        if (object != null && map != null) {
            toMap(object, map, null);
        }

    }

    /**
     * @deprecated
     */
    @Deprecated
    public static void copyProperty(Object source, Map target, boolean cascade) {
        if (Objects.nonNull(source) && Objects.nonNull(target)) {
            copyProperty(source, target, cascade, null);
        }

    }

    /**
     * @deprecated
     */
    @Deprecated
    public static void copyProperty(Object source, Map target, boolean cascade, Collection<String> ignoredFieldCol) {
        if (Objects.isNull(ignoredFieldCol)) {
            ignoredFieldCol = Sets.newHashSet();
        }

        if (cascade) {
            toMap(source, target, ignoredFieldCol);
        } else {
            Field[] fields = source.getClass().getDeclaredFields();
            ignoredFieldCol.add("serialVersionUid");

            try {
                for (Field field : fields) {
                    if (!ignoredFieldCol.contains(field.getName())) {
                        field.setAccessible(true);
                        if (field.get(source) != null) {
                            target.put(field.getName(), field.get(source));
                        }
                    }
                }
            } catch (IllegalAccessException | IllegalArgumentException var9) {
                log.error(REFLECT_ERROR, var9);
            }

        }
    }


    public static void ListMapToListObject(List<Map<String, Object>> mapList, List objectList, Class clazz) {
        if (CollUtil.isNotEmpty(mapList) && objectList != null) {

            for (Map<String, Object> stringObjectMap : mapList) {
                Map map = (Map) stringObjectMap;
                Object object = gainInstanceByReflect(clazz);
                mapToObject(map, object);
                objectList.add(object);
            }
        }

    }

    public static void ListObjectToListObject(List sourceList, List targetList, Class targetClass) {
        if (CollUtil.isNotEmpty(sourceList) && targetList != null) {

            for (Object source : sourceList) {
                Object target = gainInstanceByReflect(targetClass);
                BeanUtils.copyProperties(source, target);
                targetList.add(target);
            }
        }

    }

    public static String ListToString(List<String> list) {
        return ListToString(list, COMMA);
    }

    public static String ListToString(List<String> list, String separator) {
        return ListToString(list, separator, null);
    }

    public static String ListToString(List<String> list, String separator, String surround) {
        StringBuilder builder = new StringBuilder();
        if (CollUtil.isNotEmpty(list)) {
            int i = 0;

            for (String str : list) {
                if (i++ > 0) {
                    builder.append(separator);
                }

                if (surround != null) {
                    builder.append(surround).append(str).append(surround);
                } else {
                    builder.append(str);
                }
            }
        }

        return builder.toString();
    }


    /**
     * 单个对象转换
     *
     * @param source 来源对象
     * @param target 目标对象类
     * @param <T>    目标对象类型
     * @return 目标对象
     */
    public static <T> T sourceToTarget(Object source, Class<T> target) {
        return sourceToTarget(source, target, (Class<?>) null);
    }

    /**
     * 单个对象转换,只把源对象的 targetSuper的属性同步到目标对象
     *
     * @param source      来源对象
     * @param target      目标对象类
     * @param <T>         目标对象类型
     * @param targetSuper 目标对象的父类
     * @return 目标对象
     */
    public static <T> T sourceToTarget(Object source, Class<T> target, Class<?> targetSuper) {
        if (source == null) {
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.newInstance();
            BeanUtils.copyProperties(source, targetObject, targetSuper);
        } catch (Exception e) {
            log.error("convert error {} {} {}", source, target, targetSuper, e);
        }

        return targetObject;
    }


    public static Object gainInstanceByReflect(Class clazz) {
        String className = clazz.getName();
        return gainInstanceByReflect(className);
    }

    private static Object gainInstanceByReflect(String className) {
        Object target = null;

        try {
            target = Class.forName(className).newInstance();
        } catch (IllegalAccessException | ClassNotFoundException | InstantiationException var3) {
            log.error(REFLECT_ERROR, var3);
        }

        return target;
    }

    public static void objectToObject(Object source, Object target) {
        objectToObject(source, target, false, true, true);
    }

    public static void objectToObject(Object source, Object target, boolean ignoreNull) {
        objectToObject(source, target, ignoreNull, false, false);
    }

    public static void objectToObject(Object source, Object target, boolean ignoreNull, boolean withCreateInfo, boolean withUpdateInfo) {
        if (source != null && target != null) {
            List<String> ignorePropertiesList = Lists.newArrayList();
            if (!withCreateInfo) {
                ignorePropertiesList.add("creator");
                ignorePropertiesList.add("creatorCode");
                ignorePropertiesList.add("createTime");
            }

            if (!withUpdateInfo) {
                ignorePropertiesList.add("updater");
                ignorePropertiesList.add("updaterCode");
                ignorePropertiesList.add("updateTime");
            }

            if (ignoreNull) {
                ignoreNull(source, ignorePropertiesList);
            }

            String[] ignorePropertiesArray = new String[ignorePropertiesList.size()];
            BeanUtils.copyProperties(source, target, (String[]) ignorePropertiesList.toArray(ignorePropertiesArray));
        }
    }

    private static void ignoreNull(Object source, List<String> ignorePropertiesList) {
        Field[] fields = source.getClass().getDeclaredFields();

        try {
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.get(source) == null) {
                    ignorePropertiesList.add(field.getName());
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException var7) {
            log.error(REFLECT_ERROR, var7);
        }

    }

    public static void objectToObject(Object source, Object target, boolean ignoreNull, boolean isUpdate) {
        objectToObject(source, target, ignoreNull, !isUpdate, true);
    }

    public static void transMap2Bean(Map<String, Object> map, Object obj) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (map.containsKey(key)) {
                    Object value = map.get(key);
                    Method setter = property.getWriteMethod();
                    setter.invoke(obj, value);
                }
            }
        } catch (Exception var11) {
            log.error("Map --> Bean Error {} {}", map, obj, var11);
        }

    }

    public static <T, Q> T of(Q q, Class<T> targetClass) {
        if (Objects.isNull(q)) {
            return null;
        } else {
            T t = BeanUtils.instantiate(targetClass);
            objectToObject(q, t, true, true, true);
            return t;
        }
    }

    public static <T> T ofMap(Map<String, Object> map, Class<T> targetClass) {
        if (!Objects.isNull(map) && !map.isEmpty()) {
            T t = BeanUtils.instantiate(targetClass);
            mapToObject(map, t);
            return t;
        } else {
            return null;
        }
    }

    public static <T, Q> List<T> ofList(List<Q> sources, Class<T> targetClass) {
        if (CollUtil.isEmpty(sources)) {
            return Lists.newArrayList();
        } else {
            List<T> targetList = Lists.newArrayList();
            ListObjectToListObject(sources, targetList, targetClass);
            return targetList;
        }
    }

    public static <T> List<T> ofMapList(List<Map<String, Object>> sources, Class<T> targetClass) {
        if (CollUtil.isEmpty(sources)) {
            return Lists.newArrayList();
        } else {
            List<T> targetList = Lists.newArrayList();
            ListMapToListObject(sources, targetList, targetClass);
            return targetList;
        }
    }

    public static String[] getNullPropertyNames(Object source) {
        BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = Sets.newHashSet();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }

        String[] result = new String[emptyNames.size()];
        return (String[]) emptyNames.toArray(result);
    }

    public static void copy(Object source, Object target) {
        if (!isEmpty(source) && !isEmpty(target)) {
            String[] nullPropertyNames = getNullPropertyNames(source);
            BeanUtils.copyProperties(source, target, nullPropertyNames);
        }
    }

    public static <T> T copy(Object source, Class<T> target) {
        return copy(source, target, (Class) null);
    }

    public static <T> T copy(Object source, Class<T> target, Class<?> targetSuper) {
        if (source == null) {
            return null;
        } else {
            Object targetObject = null;

            try {
                targetObject = target.newInstance();
                BeanUtils.copyProperties(source, targetObject, targetSuper);
            } catch (Exception var5) {
                log.error("convert error {} {} {}", source, target, targetSuper, var5);
            }

            return (T) targetObject;
        }
    }

    public static <T> List<T> copy(Collection<?> sourceList, Class<T> target) {
        if (sourceList == null) {
            return null;
        } else {
            ArrayList targetList = Lists.newArrayList();

            try {
                for (Object source : sourceList) {
                    T targetObject = target.newInstance();
                    BeanUtils.copyProperties(source, targetObject);
                    targetList.add(targetObject);
                }
            } catch (Exception var6) {
                log.error("convert error {} {} {}", sourceList, target, var6);
            }

            return targetList;
        }
    }

    public static <T> T copy(Object source, Class<T> target, String... ignoreProperties) {
        if (source == null) {
            return null;
        } else {
            Object targetObject = null;

            try {
                targetObject = target.newInstance();
                BeanUtils.copyProperties(source, targetObject, ignoreProperties);
            } catch (Exception var5) {
                log.error("convert error {} {}", source, target, var5);
            }

            return (T) targetObject;
        }
    }

    public static <T> List<T> copy(Collection<?> sourceList, Class<T> target, String... ignoreProperties) {
        if (sourceList == null) {
            return null;
        } else {
            List targetList = Lists.newArrayList(sourceList.size());

            try {

                for (Object source : sourceList) {
                    T targetObject = target.newInstance();
                    BeanUtils.copyProperties(source, targetObject, ignoreProperties);
                    targetList.add(targetObject);
                }
            } catch (Exception var7) {
                log.error("convert error {} {}", sourceList, target, var7);
            }

            return targetList;
        }
    }

    public static void toMap(Object source, Map target, Collection<String> ignoredFieldCol) {
        Assert.notNull(source, "source is required");
        Assert.notNull(target, "target is required");
        if (Objects.isNull(ignoredFieldCol)) {
            ignoredFieldCol = Sets.newHashSet();
        }

        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(source.getClass());
            PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor pd : pds) {
                Method method = pd.getWriteMethod();
                if (method != null) {
                    String key = pd.getName();
                    if (!ignoredFieldCol.contains(key)) {
                        Method getter = pd.getReadMethod();
                        Object val = getter != null ? getter.invoke(source) : null;
                        target.put(key, val);
                    }
                }
            }
        } catch (InvocationTargetException | IllegalAccessException | IntrospectionException var13) {
            log.error(REFLECT_ERROR, var13);
        }

    }

    protected static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        } else if (obj instanceof Optional) {
            return !((Optional) obj).isPresent();
        } else if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        } else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        } else if (obj instanceof Collection) {
            return ((Collection) obj).isEmpty();
        } else {
            return obj instanceof Map && ((Map) obj).isEmpty();
        }
    }

}
